package com.zn.socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.Socket;

/**
 * Created by yinjiawei on 2018/7/12.
 */
public class SocketHandler implements SocketStatusListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(SocketHandler.class);
    private static SocketHandler socketHandler;

    public Socket socket=null;

    private ReaderTask reader;

    private WriterTask writer;

    public SocketHandler(String host,int port) throws IOException{
        this.socket = new Socket(host, port);
        this.socket.setTcpNoDelay(true);
        this.socket.setKeepAlive(true);
        this.socket.setTcpNoDelay(true);
        this.reader = new ReaderTask(socket);
        this.writer = new WriterTask(socket);
        listen(true);
        onSocketStatusChanged(socket, STATUS_OPEN, null);
    }

    public static SocketHandler getInstance(String host,int port) throws IOException{
        if (socketHandler == null) {
            synchronized (SocketHandler.class) {
                if (socketHandler == null) {
                    socketHandler = new SocketHandler(host,port);
                }
            }
        }
        return socketHandler;
    }

    public static void setEmpty(){
        socketHandler=null;
    }

    /**
     * 判断是否断开连接，断开返回true,没有返回false
     * @return
     */
    public Boolean isServerClose(){
        try{
            //默认值为 false。为 true 时, 表示支持发送一个字节的 TCP 紧急数据. Socket 类的 sendUrgentData(int data) 方法用于发送一个字节的 TCP紧急数据。
            //为 false的这种情况下, 当接收方收到紧急数据时不作任何处理, 直接将其丢弃. 如果用户希望发送紧急数据, 服务端应该把 OOBINLINE 设为 true。
            //发送1个字节的紧急数据，默认情况下，服务器端没有开启紧急数据处理，不影响正常通信
            this.socket.sendUrgentData(0xFF);
            return false;
        }catch(Exception se){
            return true;
        }
    }

    /**
     * sendMessage:(这里用一句话描述这个方法的作用). <br/>
     * TODO(这里描述这个方法适用条件 – 可选).<br/>
     */
    public void sendMessage(String msg) {
        this.writer.send(msg+"|\n");
    }

    public void listen(boolean isListen)
    {
        this.reader.startListener(this);

    }

    public void shutDown() {

        if(!socket.isClosed() && socket.isConnected())
        {
            try {
                writer.finish();
                reader.finish();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
                onSocketStatusChanged(socket, STATUS_CLOSE, e);
            }finally{
                reader = null;
                writer = null;
                LOGGER.info("Socket连接已关闭！！");
            }
        }
    }

    @Override
    public void onSocketStatusChanged(Socket socket,int status, Exception e) {
        switch (status) {
            case SocketStatusListener.STATUS_CLOSE:
            case SocketStatusListener.STATUS_RESET:
            case SocketStatusListener.STATUS_PIP_BROKEN:
                shutDown();
                break;

            default:
                break;
        }
    }


}
